home *** CD-ROM | disk | FTP | other *** search
/ Mac Mania 5 / MacMania 5.toast / / Internet software / NewsWatcher / NW Source / Source / next.c < prev    next >
Text File  |  1997-01-09  |  14KB  |  502 lines

  1. /*----------------------------------------------------------------------------
  2.  
  3.     next.c
  4.  
  5.     This module handles the next article, thread, and group commands.
  6.     
  7.     Copyright © 1994-1997, Northwestern University.
  8.  
  9. ----------------------------------------------------------------------------*/
  10.  
  11. #include <stdio.h>
  12.  
  13. #include "glob.h"
  14. #include "article.h"
  15. #include "newswatcher.h"
  16. #include "mark.h"
  17. #include "next.h"
  18. #include "subject.h"
  19. #include "dialog.h"
  20. #include "dummy.h"
  21. #include "help.h"
  22. #include "group.h"
  23. #include "biglist.h"
  24.  
  25.  
  26.  
  27. /*----------------------------------------------------------------------------
  28.     OpenNextUnreadGroup 
  29.     
  30.     Open the subject window for the next group with unread articles in a 
  31.     group window.
  32.             
  33.     Entry:    wind = pointer to group window.
  34.             item = the item in the group list at which to start the
  35.                 search for the next group with unread articles.
  36.                 
  37.     Exit:    function result = error code.
  38. ----------------------------------------------------------------------------*/
  39.  
  40. static OSErr OpenNextUnreadGroup (WindowPtr wind, long item)
  41. {
  42.     TWindow **info;
  43.     TGroupWindowKind groupKind;
  44.     TGroup **groupArray;
  45.     BigListRef groupList;
  46.     long index, numItems;
  47.     OSErr err = noErr;
  48.     Boolean hasArts;
  49.  
  50.     info = (TWindow**)GetWRefCon(wind);
  51.     groupKind = (**info).groupKind;
  52.     groupArray = (**info).groupArray;
  53.     groupList = (**info).groupList;
  54.     numItems = BigLGetNumItems(groupList);
  55.     for (; item < numItems; item++) {
  56.         index = BigLGetData(groupList, item);
  57.         if ((groupKind == kUserGroup && (*groupArray)[index].unread != nil) ||
  58.             groupKind != kUserGroup) 
  59.         {
  60.             BigLSelectOnlyOne(groupList, item);
  61.             BigLScrollItemIntoView(groupList, item, kBigLScrollToTop,
  62.                 kBigLScrollToTop);
  63.             HandleUpdate(wind);
  64.             err = OpenGroupItem(wind, item, gPrefs.maxFetch, &hasArts);
  65.             if (err != noErr) return err;
  66.             if (err == noErr && hasArts) return noErr;
  67.         }
  68.     }
  69.     if (gPrefs.beepAtEndOfLists) SysBeep(0);
  70.     return noErr;
  71. }
  72.  
  73.  
  74.  
  75. /*----------------------------------------------------------------------------
  76.     OpenNextUnreadArticle 
  77.     
  78.     Open the article window for the next unread article in a subject window.
  79.             
  80.     Entry:    wind = pointer to subject window.
  81.             item = the item in the subject list at which to start
  82.                 the search for the next unread article.
  83.             threadOrdinal = ordinal of article within thread at which
  84.                 to start the search if the item is a collapsed thread.
  85.             reuse = pointer to article window to be reused, or nil to
  86.                 open new article window.
  87.             onlySelect = true to only select the next unrread article
  88.                 in the subject window, but not open it.
  89.                 
  90.     Exit:    function result = error code.
  91. ----------------------------------------------------------------------------*/
  92.  
  93. static OSErr OpenNextUnreadArticle (WindowPtr wind, long item, 
  94.     long threadOrdinal, WindowPtr reuse, Boolean onlySelect)
  95. {
  96.     TWindow **info;
  97.     TSubject **subjectArray;
  98.     BigListRef subjectList;
  99.     long numItems, index, i;
  100.     Boolean collapsed;
  101.     WindowPtr child, parent;
  102.     OSErr err = noErr;
  103.  
  104.     info = (TWindow**)GetWRefCon(wind);
  105.     subjectArray = (**info).subjectArray;
  106.     subjectList = (**info).subjectList;
  107.     numItems = BigLGetNumItems(subjectList);
  108.     while (item < numItems) {
  109.         index = BigLGetData(subjectList, item);
  110.         if (threadOrdinal > (*subjectArray)[index].threadLength) {
  111.             item++;
  112.             threadOrdinal = 1;
  113.         } else {
  114.             collapsed = (*subjectArray)[index].collapsed;
  115.             if (collapsed) 
  116.                 for (i = 1; i < threadOrdinal; i++) 
  117.                     index = (*subjectArray)[index].nextInThread;
  118.             if (!(*subjectArray)[index].read) { 
  119.                 BigLSelectOnlyOne(subjectList, item);
  120.                 BigLScrollItemIntoView(subjectList, item, kBigLScrollToTop,
  121.                     kBigLScrollToTop);
  122.                 HandleUpdate(wind);
  123.                 if (onlySelect) return noErr;
  124.                 err = OpenSubjectItem(wind, item, threadOrdinal, reuse, &child);
  125.                 if (err != noErr) return err;
  126.                 if (child != nil) return noErr;
  127.             }
  128.             if (collapsed) {
  129.                 threadOrdinal++;
  130.             } else {
  131.                 item++;
  132.                 threadOrdinal = 1;
  133.             }
  134.         }
  135.     }
  136.     if (reuse != nil) DoClose(reuse);
  137.     if (gPrefs.stopAtEndOfSubjectList) {
  138.         if (gPrefs.beepAtEndOfLists) SysBeep(0);
  139.     } else {
  140.         parent = (**info).parentWindow;
  141.         index = (**info).parentGroup;
  142.         err = DoClose(wind);
  143.         if (err != noErr) return err;
  144.         wind = parent;
  145.         item = FindParentItem(wind, index);
  146.         item++;
  147.         return OpenNextUnreadGroup(wind, item);
  148.     }
  149.     return noErr;
  150. }
  151.  
  152.  
  153.  
  154. /*----------------------------------------------------------------------------
  155.     DoNextArticle 
  156.     
  157.     Handle the "Next Article" command.
  158.             
  159.     Entry:    wind = pointer to article, subject, or group window.
  160.     
  161.     Exit:    function result = error code.
  162. ----------------------------------------------------------------------------*/
  163.  
  164. OSErr DoNextArticle (WindowPtr wind)
  165. {
  166.     TWindow **info;
  167.     WindowPtr parent;
  168.     long index, item, threadOrdinal;
  169.     TSubject **subjectArray, theSubject;
  170.     Boolean returnToSubjectWindow = false;
  171.     OSErr err = noErr;
  172.     
  173.     info = (TWindow**)GetWRefCon(wind);
  174.     
  175.     switch ((**info).kind) {
  176.     
  177.         case kArticle:
  178.         
  179.             parent = (**info).parentWindow;
  180.             if (parent == nil) return noErr;
  181.             index = (**info).parentSubject;
  182.             info = (TWindow**)GetWRefCon(parent);
  183.             subjectArray = (**info).subjectArray;
  184.             theSubject = (*subjectArray)[index];
  185.             if (theSubject.collapsed) {
  186.                 item = FindParentItem(parent, theSubject.threadHeadIndex);
  187.                 threadOrdinal = theSubject.threadOrdinal + 1;
  188.             } else {
  189.                 item = FindParentItem(parent, index);
  190.                 item++;
  191.                 threadOrdinal = 1;
  192.             }
  193.             
  194.             if (gPrefs.returnToSubjectWindow) {
  195.                 returnToSubjectWindow = true;
  196.                 while (true) {
  197.                     if (theSubject.threadOrdinal == theSubject.threadLength) break;
  198.                     theSubject = (*subjectArray)[theSubject.nextInThread];
  199.                     if (!theSubject.read) {
  200.                         returnToSubjectWindow = false;
  201.                         break;
  202.                     }
  203.                 }
  204.             }
  205.             
  206.             if (returnToSubjectWindow) {
  207.                 err = DoClose(wind);
  208.                 if (err != noErr) return err;
  209.                 return OpenNextUnreadArticle(parent, item, threadOrdinal, nil, true);
  210.             } else if (gPrefs.reuseArticleWinds) {
  211.                 return OpenNextUnreadArticle(parent, item, threadOrdinal, wind, false);
  212.             } else {
  213.                 err = DoClose(wind);
  214.                 if (err != noErr) return err;
  215.                 err = ShowDummyWindow();
  216.                 if (err != noErr) return err;
  217.                 err = OpenNextUnreadArticle(parent, item, threadOrdinal, nil, false);
  218.                 HideDummyWindow();
  219.                 return err;
  220.             }
  221.             
  222.         case kSubject:
  223.         
  224.             item = BigLGetFirstSelectedItem((**info).subjectList);
  225.             if (item < 0) item = 0;
  226.             threadOrdinal = 1;
  227.             return OpenNextUnreadArticle(wind, item, threadOrdinal, nil, false);
  228.             
  229.         case kGroup:
  230.         
  231.             item = BigLGetFirstSelectedItem((**info).groupList);
  232.             if (item < 0) item = 0;
  233.             return OpenNextUnreadGroup(wind, item);
  234.             
  235.     }
  236.     return noErr;
  237. }
  238.  
  239.  
  240.  
  241. /*----------------------------------------------------------------------------
  242.     DoNextThread 
  243.     
  244.     Handle the "Next Thread" command.
  245.             
  246.     Entry:    wind = pointer to article, subject, or group window.
  247.     
  248.     Exit:    function result = error code.
  249. ----------------------------------------------------------------------------*/
  250.  
  251. OSErr DoNextThread (WindowPtr wind)
  252. {
  253.     TWindow **info;
  254.     WindowPtr parent;
  255.     long index, item;
  256.     TSubject **subjectArray, theSubject;
  257.     BigListRef subjectList;
  258.     OSErr err = noErr;
  259.     
  260.     info = (TWindow**)GetWRefCon(wind);
  261.     
  262.     switch ((**info).kind) {
  263.     
  264.         case kArticle:
  265.         
  266.             parent = (**info).parentWindow;
  267.             if (parent == nil) return noErr;
  268.             index = (**info).parentSubject;
  269.             info = (TWindow**)GetWRefCon(parent);
  270.             subjectArray = (**info).subjectArray;
  271.             theSubject = (*subjectArray)[index];
  272.             MarkThread(parent, theSubject.threadHeadIndex, true);
  273.             item = FindParentItem(parent, theSubject.threadHeadIndex);
  274.             if (theSubject.collapsed) {
  275.                 item++;
  276.             } else {
  277.                 item += theSubject.threadLength;
  278.             }
  279.             
  280.             if (gPrefs.reuseArticleWinds) {
  281.                 return OpenNextUnreadArticle(parent, item, 1, wind, false);
  282.             } else {
  283.                 err = DoClose(wind);
  284.                 if (err != noErr) return err;
  285.                 err = ShowDummyWindow();
  286.                 if (err != noErr) return err;
  287.                 err = OpenNextUnreadArticle(parent, item, 1, nil, false);
  288.                 HideDummyWindow();
  289.                 return err;
  290.             }
  291.             
  292.         case kSubject:
  293.         
  294.             subjectList = (**info).subjectList;
  295.             subjectArray = (**info).subjectArray;
  296.             item = BigLGetFirstSelectedItem(subjectList);
  297.             if (item >= 0) {
  298.                 index = BigLGetData(subjectList, item);
  299.                 theSubject = (*subjectArray)[index];
  300.                 MarkThread(wind, theSubject.threadHeadIndex, true);
  301.                 if (theSubject.collapsed) {
  302.                     item++;
  303.                 } else {
  304.                     item += theSubject.threadLength + 1 - theSubject.threadOrdinal;
  305.                 }
  306.             } else {
  307.                 item = 0;
  308.             }
  309.             return OpenNextUnreadArticle(wind, item, 1, nil, false);
  310.             
  311.         case kGroup:
  312.         
  313.             item = BigLGetFirstSelectedItem((**info).groupList);
  314.             if (item < 0) item = 0;
  315.             return OpenNextUnreadGroup(wind, item);
  316.             
  317.     }
  318.     return noErr;
  319. }
  320.  
  321.  
  322.  
  323. /*----------------------------------------------------------------------------
  324.     DoNextGroup 
  325.     
  326.     Handle the "Next Group" command.
  327.             
  328.     Entry:    wind = pointer to article, subject, or group window.
  329.     
  330.     Exit:    function result = error code.
  331. ----------------------------------------------------------------------------*/
  332.  
  333. OSErr DoNextGroup (WindowPtr wind)
  334. {
  335.     TWindow **info;
  336.     WindowPtr parent;
  337.     long item, index;
  338.     OSErr err = noErr;
  339.     
  340.     info = (TWindow**)GetWRefCon(wind);
  341.     
  342.     switch ((**info).kind) {
  343.     
  344.         case kArticle:
  345.         
  346.             parent = (**info).parentWindow;
  347.             if (parent == nil) return noErr;
  348.             err = DoClose(wind);
  349.             if (err != noErr) return err;
  350.             wind = parent;
  351.             info = (TWindow**)GetWRefCon(wind);
  352.             /* fall through to kSubject case */;
  353.             
  354.         case kSubject:
  355.         
  356.             MarkAllSubjects(wind, true);
  357.             parent = (**info).parentWindow;
  358.             index = (**info).parentGroup;
  359.             err = DoClose(wind);
  360.             if (err != noErr) return err;
  361.             wind = parent;
  362.             item = FindParentItem(wind, index);
  363.             item++;
  364.             return OpenNextUnreadGroup(wind, item);
  365.             
  366.         case kGroup:
  367.         
  368.             item = BigLGetFirstSelectedItem((**info).groupList);
  369.             if (item < 0) item = 0;
  370.             return OpenNextUnreadGroup(wind, item);
  371.             
  372.     }
  373.     return noErr;
  374. }
  375.  
  376.  
  377.  
  378. /*----------------------------------------------------------------------------
  379.     OpenPrevOrNextArticle 
  380.     
  381.     Open the previous or next article.
  382.             
  383.     Entry:    parent = pointer to parent subject window.
  384.             item = the parent item in the subject window for the article.
  385.             threadOrdinal = ordinal of article within thread if thread
  386.                 is collapsed, else 1.
  387.             reuse = pointer to article window to be reused, or nil to
  388.                 open new article window.
  389.             dir = direction = -1 to open previous article, +1 to open
  390.                 next article.
  391.                 
  392.     Exit:    function result = error code.
  393. ----------------------------------------------------------------------------*/
  394.  
  395. static OSErr OpenPrevOrNextArticle (WindowPtr parent, long item, 
  396.     long threadOrdinal, WindowPtr reuse, short dir)
  397. {
  398.     TWindow **info;
  399.     TSubject **subjectArray;
  400.     BigListRef subjectList;
  401.     long numItems, index;
  402.     WindowPtr child;
  403.     OSErr err = noErr;
  404.  
  405.     info = (TWindow**)GetWRefCon(parent);
  406.     subjectArray = (**info).subjectArray;
  407.     subjectList = (**info).subjectList;
  408.     numItems = BigLGetNumItems(subjectList);
  409.     index = BigLGetData(subjectList, item);
  410.     while (true) {
  411.         if ((*subjectArray)[index].collapsed) {
  412.             threadOrdinal += dir;
  413.             if (threadOrdinal > (*subjectArray)[index].threadLength) {
  414.                 item++;
  415.                 if (item >= numItems) break;
  416.                 threadOrdinal = 1;
  417.                 index = BigLGetData(subjectList, item);
  418.             } else if (threadOrdinal <= 0) {
  419.                 item--;
  420.                 if (item < 0) break;
  421.                 index = BigLGetData(subjectList, item);
  422.                 if ((*subjectArray)[index].collapsed) {
  423.                     threadOrdinal = (*subjectArray)[index].threadLength;
  424.                 } else {
  425.                     threadOrdinal = 1;
  426.                 }
  427.             }
  428.         } else {
  429.             item += dir;
  430.             if (item >= numItems || item < 0) break;
  431.             index = BigLGetData(subjectList, item);
  432.             if (dir == -1 && (*subjectArray)[index].collapsed) {
  433.                 threadOrdinal = (*subjectArray)[index].threadLength;
  434.             } else {
  435.                 threadOrdinal = 1;
  436.             }
  437.         }
  438.         BigLSelectOnlyOne(subjectList, item);
  439.         BigLScrollItemIntoView(subjectList, item, kBigLScrollToTop,
  440.             kBigLScrollToTop);
  441.         HandleUpdate(parent);
  442.         err = OpenSubjectItem(parent, item, threadOrdinal, reuse, &child);
  443.         if (err != noErr) return err;
  444.         if (child != nil) return noErr;
  445.     }
  446.     SysBeep(0);
  447.     return noErr;
  448. }
  449.  
  450.  
  451. /*----------------------------------------------------------------------------
  452.     GoBackwardsOrForwardsOneArticle
  453.     
  454.     Go backwards or forwards one article.
  455.     
  456.     Entry:    wind = pointer to article window.
  457.             dir = direction = -1 to go backwards, +1 to go forwards.
  458.             
  459.     Exit:    function result = error code.
  460. ----------------------------------------------------------------------------*/
  461.  
  462. OSErr GoBackwardsOrForwardsOneArticle (WindowPtr wind, short dir)
  463. {
  464.     TWindow **info;
  465.     WindowPtr parent;
  466.     long index, item, threadOrdinal;
  467.     TSubject **subjectArray, theSubject;
  468.     Boolean returnToSubjectWindow = false;
  469.     OSErr err = noErr;
  470.     
  471.     info = (TWindow**)GetWRefCon(wind);
  472.     if ((**info).kind != kArticle) return noErr;
  473.     parent = (**info).parentWindow;
  474.     if (parent == nil) return noErr;
  475.     index = (**info).parentSubject;
  476.     info = (TWindow**)GetWRefCon(parent);
  477.     subjectArray = (**info).subjectArray;
  478.     theSubject = (*subjectArray)[index];
  479.     if (theSubject.collapsed) {
  480.         item = FindParentItem(parent, theSubject.threadHeadIndex);
  481.         threadOrdinal = theSubject.threadOrdinal;
  482.     } else {
  483.         item = FindParentItem(parent, index);
  484.         threadOrdinal = 1;
  485.     }
  486.     if (gPrefs.reuseArticleWinds) {
  487.         err = OpenPrevOrNextArticle(parent, item, threadOrdinal, wind, dir);
  488.     } else {
  489.         err = DoClose(wind);
  490.         if (err != noErr) goto exit;
  491.         err = ShowDummyWindow();
  492.         if (err != noErr) goto exit;
  493.         err = OpenPrevOrNextArticle(parent, item, threadOrdinal, nil, dir);
  494.         HideDummyWindow();
  495.     }
  496.  
  497. exit:
  498.  
  499.     KillBalloon();
  500.     return err;
  501. }
  502.